package wang.datahub.mylang;

import wang.datahub.mylang.parser.MyLangBaseVisitor;
import wang.datahub.mylang.parser.MyLangParser;

import java.util.Hashtable;
import java.util.List;
import java.util.stream.Collectors;

public class MLVistor extends MyLangBaseVisitor {
//    Hashtable<String, MyLangParser.FunctionDeclContext> sympoltable = new Hashtable<>();
    Hashtable<String,Symbol> _sympoltable = new Hashtable<>();

    @Override
    public Object visitPrimary(MyLangParser.PrimaryContext ctx) {
        Object res = null;
        if(ctx.NUMBER_LITERAL() != null){
            res = Integer.parseInt(ctx.NUMBER_LITERAL().getText().trim().replace("\"",""));
//            return res;
        }else if(ctx.STRING_LITERAL() != null){
            res = ctx.STRING_LITERAL().getText();
//            return res;
        }else if(ctx.functionCall() !=null){
            return visitFunctionCall(ctx.functionCall());
        }else if(ctx.identifier() !=null){
            return visitIdentifier(ctx.identifier());
        }else if(ctx.singleExpression() != null){
            return visitSingleExpression(ctx.singleExpression());
        }
//        return visitPrimary(ctx);
        return res;
    }

    @Override
    public Object visitVariableDecl(MyLangParser.VariableDeclContext ctx) {
        String varName = ctx.identifier().getText();
        if(_sympoltable.get(varName) == null){
            System.out.println("define var ==> " + varName);
            Symbol symbol = new Symbol(varName, Symbol.SymbolType.VAR,ctx);
            _sympoltable.put(varName,symbol);
            if(ctx.AssignmentOp() != null){

                Object o = visitPrimary(ctx.primary());
                symbol.setValue(o);
            }
            return null;
        }
        return super.visitVariableDecl(ctx);
    }

    @Override
    public Object visitFunctionDecl(MyLangParser.FunctionDeclContext ctx) {
        String functionName = ctx.identifier().getText();
        if(_sympoltable.get(functionName) == null){
            System.out.println("define function ==> " + functionName);
//            sympoltable.put(ctx.identifier().getText(),ctx);
            Symbol symbol = new Symbol(functionName, Symbol.SymbolType.FUNCTION,ctx);
            _sympoltable.put(functionName,symbol);
            return null;
        }
        //return null;
        return super.visitFunctionDecl(ctx);
    }

    @Override
    public Object visitFunctionCall(MyLangParser.FunctionCallContext ctx) {
        String functionName = ctx.identifier().getText();
        if("print".equals(functionName)){
//            String parStr = ctx.parameterList().getText();
//            if(parStr.startsWith("\"")){
//                parStr = parStr.substring(1,parStr.length()-1);
//            }
            System.out.println("...........");
            List<Object> f =ctx.parameterList().singleExpression().stream().map(it->{
                                                                Symbol symbol = _sympoltable.get(it.getText());
                                                                if(symbol != null){
                                                                    return symbol.getValue();
                                                                }else{
                                                                    return it.getText();
                                                                }
                                                        }).collect(Collectors.toList());
            f.stream().forEach(System.out::println);

            //System.out.println(parStr);
            return null;
        }else{
            System.out.println("run function ==>"+functionName);
            MyLangParser.FunctionDeclContext fdc = (MyLangParser.FunctionDeclContext) _sympoltable.get(functionName).getParseTree();
                    //sympoltable.get(functionName);
            if(fdc==null){
                throw new RuntimeException("undefine function ...." + functionName);
            }
            super.visitFunctionDecl(fdc);
        }
        return super.visitFunctionCall(ctx);
    }
}
